package com.peaksport.framework.metadata.parse;


import java.io.Serializable;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.JoinColumn;
import javax.persistence.Transient;

import com.peaksport.framework.exception.PKDevException;
import com.peaksport.framework.map.ListMap;
import com.peaksport.framework.map.NoCaseMap;
import com.peaksport.framework.metadata.filter.FilterInfo;
import com.peaksport.framework.metadata.filter.FilterItemCollection;
import com.peaksport.framework.metadata.filter.FilterItemInfo;
import com.peaksport.framework.metadata.selector.SelectorItemCollection;
import com.peaksport.framework.metadata.selector.SelectorItemInfo;
import com.peaksport.framework.metadata.sorter.SorterItemCollection;
import com.peaksport.framework.metadata.sorter.SorterItemInfo;
import com.peaksport.framework.metadata.venum.MergeLogicEnum;
import com.peaksport.framework.metadata.venum.ValueTypeEnum;
import com.peaksport.framework.metadata.view.EntityViewInfo;
import com.peaksport.framework.util.PKClassUtils;
import com.peaksport.framework.util.PKPublicUtils;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

/**
 *  解析实体Entity对象
 * 
 * 
 * @author jinbin_guo  2019年4月16日 上午10:58:48
 *
 */
@Slf4j
public class EntityParse {


    private static final String CR = PKPublicUtils.CR;

    private StringBuilder sqlSelectField = new StringBuilder("select ");
    private StringBuilder sqlFromTable = new StringBuilder("from ");
    private StringBuilder sqlInnerTable = new StringBuilder();
    private StringBuilder sqlWhere = new StringBuilder("where ");
    private StringBuilder sqlOrderBy = new StringBuilder("order by ");

    /** 实体对象属性 - 实际表字段的映射 */
    private Map<String,String>  propertyFieldMapping = new HashMap<>();
    /** 表别名序号*/
    private int tableAliasIdx = 0;
    private int selectFieldCount =  0;
    
    /** select对象长字段别名间隔符号*/
    private static final String longFieldAliasSplit = ".";

    
    /**
     *   获取默认的所有CoreBaseEntity实体的selector,以'*'表示所有
     *   对于集合List<CoreBaseEntity>的也会解析出'*'
     *
     *   如:  *,entrys.*
     * @param entityClass  CoreBaseEntity实体类型
     * @return
     */
    public SelectorItemCollection  getDefaultSelectorItemCol(Class<?> entityClass) {
        return _getDefaultSelectorItemCol(null,entityClass);
    }

    /**
     *
     * @param parentFlag 父类的标识
     * @param entityClass
     * @return
     */
	private SelectorItemCollection _getDefaultSelectorItemCol(String parentFlag, Class<?> entityClass) {
        SelectorItemCollection sic = new SelectorItemCollection();
        NoCaseMap<Field> mapFieldMapping = PKClassUtils.getAllField(entityClass);
        Set<String> setKey = mapFieldMapping.keySet();
        Iterator<String> itKey = setKey.iterator();
        String selector = parentFlag == null ? "*" : (parentFlag + ".*");
        sic.addSelectorItemInfo(new SelectorItemInfo(selector));
        while (itKey.hasNext()) {
            String key = itKey.next();
            Field field = mapFieldMapping.get(key);
            if (List.class.isAssignableFrom(field.getType()))  {
                Class<?> genericClass = PKClassUtils.getGenericClass(field);
                parentFlag = parentFlag == null ? field.getName() : (parentFlag + "." + field.getName());
                sic.addCollection(_getDefaultSelectorItemCol(parentFlag,genericClass));
            }
        }
        return sic;
    }
	
	/**
	 * 将EntityViewInfo转换成对应的SQL
	 * @param entityClass
	 * @param entityViewInfo
	 * @return
	 */
	public String toSQL(Class<?> entityClass, EntityViewInfo entityViewInfo) {
		long curTime = System.currentTimeMillis();
        StringBuffer sql = new StringBuffer();
        SelectorItemCollection sic = entityViewInfo.getSelectorItemCol();
        if (sic == null || sic.size() == 0) {
            sic = getDefaultSelectorItemCol(entityClass);
            entityViewInfo.setSelectorItemCol(sic);
        }
        //1. 把SelectItemCollection转换成jsonDataTpl数据模板 
        //检查&重新解析带*的selector
        sic = reParseSelector(entityClass, sic);
        Map<String,Object> jsonDataTpl = selector2JsonDataTpl(sic);
        
        //2. 把filterInfo内的属性转换成json格式的数据模板内
        FilterInfo filterInfo = entityViewInfo.getFilterInfo();
        //将管理单元数据过滤合并
        FilterItemInfo cuFilterItemInfo = entityViewInfo.getDefaultCUFilterItemInfo();
        if (cuFilterItemInfo != null) {
            FilterInfo cuFilterInfo = new FilterInfo();
            cuFilterInfo.addFilterItemInfo(cuFilterItemInfo);
            filterInfo.addMergeFilterInfo(cuFilterInfo, MergeLogicEnum.AND);
        }
        filter2JsonDataTpl(jsonDataTpl, filterInfo);
        
        //3. 把sorter内的属性转换成json格式的数据模板内
        SorterItemCollection sorterItemCol = entityViewInfo.getSorterItemCol();
        sorter2JsonDataTpl(jsonDataTpl, sorterItemCol);
        //4. 将jsonDataTpl数据模板转化成SelectorMap对象,SelectMap承载select语句的信息
        SelectorMap selectorMap = parseJsonDataTpl2SelectorMap(jsonDataTpl, entityClass, null, null);
        
        //5. 解析成对应SQL语句
        // 5.1 解析from
        String mainTableName = PKClassUtils.getTableName(selectorMap.getEntityClass());
        String tableAlias = selectorMap.getTableAlias();
        sqlFromTable.append(mainTableName).append(" ").append(tableAlias).append(" ");
        // 5.2 解析select 字段
        ListMap<SelectorField> lstSelectorField = selectorMap.getSelectorFields();
        for (int i = 0, len = lstSelectorField.size(); i < len; i++) {
            SelectorField selectorField = lstSelectorField.get(i);
            String fieldName = selectorField.getFieldName();
            String fieldAlias = selectorField.getShortFieldAlias();
            sqlSelectField.append(tableAlias).append(".").append(fieldName).append(" \"").append(fieldAlias).append("\",");
            selectFieldCount++;
            if (selectFieldCount % 5 == 0) sqlSelectField.append(CR);
        }
    
        
        //5.3 解析左右连接left join、right join
        ListMap<SelectorMap> lstRTblSelectorMap = selectorMap.getRTblSelectorMap();
        for (int i = 0, len = lstRTblSelectorMap.size(); i < len; i++) {
            SelectorMap rTblSelectorMap = lstRTblSelectorMap.get(i);
            builderSQL(rTblSelectorMap);
        }
        
        //6. 合并sql语句
        sqlSelectField.replace(sqlSelectField.lastIndexOf(","),sqlSelectField.length(),""); 
        sql.append(sqlSelectField).append(CR).append(sqlFromTable).append(CR).append(sqlInnerTable);
        //解析where 条件
        if (filterInfo != null && !filterInfo.isEmpty()) {
            reParseFilterInfo(filterInfo);
            sql.append(sqlWhere).append(filterInfo.toSQL()).append(CR);
        }
        //解析orderBy 排序
        if (sorterItemCol != null && !sorterItemCol.isEmpty()) {
            reParseSorter(sorterItemCol);
            sql.append(sqlOrderBy).append(sorterItemCol.toSQL());
        }
        log.debug("Entity实体[%s],解析SQL语句耗费时间:%l", entityClass.getName(),System.currentTimeMillis()-curTime);
        return sql.toString();
    }

	 /**
     * 检查&重新解析带*的selector
     * 1. 检查selector字段的合法性，是否存在对应的实体对象中
     * 2. 对带*的解析对应的全字段
     * 3. 对未指定具体字段的对象,默认指定其字段id
     * @param entityClass
     * @param sic
     * @return
     */
    private SelectorItemCollection reParseSelector(Class<?> entityClass, SelectorItemCollection sic) {
        //主对象的字段映射
    	NoCaseMap<Field> mainFieldMapping = PKClassUtils.getAllField(entityClass);
        SelectorItemCollection newSic = new SelectorItemCollection();
        for (int i = 0, len = sic.size(); i < len; i++) {
            SelectorItemInfo sii = sic.get(i);
            String propertyName = sii.getPropertyName();
            //主对象上的 *
            if (propertyName.indexOf("*") > -1 && propertyName.indexOf(".") == -1) {
                Set<String> setKeyField = mainFieldMapping.keySet();
                Iterator<String> itKeyField = setKeyField.iterator();
                while (itKeyField.hasNext()) {
                    String fieldName = itKeyField.next();
                    Field field = mainFieldMapping.get(fieldName);
                    if (PKClassUtils.isExtendBaseEntity(field.getType()))
                        fieldName = fieldName + ".id";
                    else if (List.class.isAssignableFrom(field.getType())) {
                       continue;
                    }
                    SelectorItemInfo newSii = new SelectorItemInfo(fieldName);
                    newSic.addSelectorItemInfo(newSii);
                }
            // 关联对象或关联分录  如：xxx.*; xxx.id;xxx.number;xxx.yy.* ;xxx.yy.name;....
            } else if (propertyName.indexOf(".") > -1) {
                //拆分带.的属性
                String[] splitPropertyName = propertyName.split("\\.");
                //第一个属性从主对象上获取
                Field field = mainFieldMapping.get(splitPropertyName[0]);
                if (field == null )
                    throw PKDevException.throwException("Entity实体类[%s]不存在属性[%s]",entityClass.getName(),propertyName);
                Class<?> clazz = null;
                if (List.class.isAssignableFrom(field.getType())) {
                    clazz = PKClassUtils.getGenericClass(field);

                } else {
                    clazz = field.getType();
                }
                NoCaseMap<Field> newMapFieldMapping = PKClassUtils.getAllField(clazz);
                for (int j = 1, jlen = splitPropertyName.length-1; j < jlen; j++) {
                    field = newMapFieldMapping.get(splitPropertyName[j]);
                    if (field == null )
                        throw PKDevException.throwException("Entity实体类[%s]不存在属性[%s]",entityClass.getName(),propertyName);
                    if (field.getType().isAssignableFrom(Set.class)) {
                        clazz = PKClassUtils.getGenericClass(field);
                    } else {
                        clazz = field.getType();
                    }
                    newMapFieldMapping = PKClassUtils.getAllField(clazz);
                }

                if (propertyName.indexOf("*") > -1) {
                    Set<String> setKeyField = newMapFieldMapping.keySet();
                    Iterator<String> itKeyField = setKeyField.iterator();
                    propertyName = propertyName.replace("*", "");
                    while (itKeyField.hasNext()) {
                        String key = itKeyField.next();
                        String fieldName = propertyName + key;
                        field = newMapFieldMapping.get(key);
                        if (PKClassUtils.isExtendBaseEntity(field.getType()))
                            fieldName = fieldName + ".id";
                        SelectorItemInfo newSii = new SelectorItemInfo(fieldName);
                        newSic.addSelectorItemInfo(newSii);
                    }
                } else {
                    field = newMapFieldMapping.get(splitPropertyName[splitPropertyName.length-1]);
                    if (field == null)
                        throw PKDevException.throwException("Entity实体类[%s]不存在属性[%s]",entityClass.getName(),propertyName);
                    if (PKClassUtils.isExtendBaseEntity(field.getType()))
                        sii = new SelectorItemInfo(sii.getPropertyName() + ".id");
                    newSic.addSelectorItemInfo(sii);
                }

            } else {
                if (mainFieldMapping.get(propertyName) == null) throw PKDevException.throwException("Entity实体类[%s]不存在属性[%s]",entityClass.getName(),propertyName);
                newSic.addSelectorItemInfo(sii);
            }


        }

        return newSic;
    }
    
    /**
     * 将selectorItemCollection转换成jsonDataTpl数据模板
     * @param sic
     * @return
     */
    private Map<String,Object> selector2JsonDataTpl(SelectorItemCollection sic) {
         Map<String,Object> jsonDataTpl = new HashMap<>();
         for (int i = 0, len = sic.size(); i < len; i++) {
            SelectorItemInfo sii = sic.get(i);
            String propertyName = sii.getPropertyName();
             jsonDataTpl = property2JsonDataTpl(jsonDataTpl,propertyName,JsonTplDataType.Selector);
        }
        return jsonDataTpl;
    }
    
    /**
     *  将属性字段转换成json格式的数据模板
     *  
     * @param jsonDataTpl 目标数据模板
     * @param property 属性值
     * @param type 类型，Selector,Filter,Sorter
     * @return
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
	private Map<String,Object> property2JsonDataTpl(Map<String,Object> jsonDataTpl, String property, JsonTplDataType type) {
        if (property.indexOf(".") == -1) {
            if (jsonDataTpl.get(property) == null)
                jsonDataTpl.put(property,type);
        } else {
            String[] split = property.split("\\.");
            Map<String,Object> cur = jsonDataTpl;
            for (int i = 0, len = split.length; i < len; i++) {
                if (i == len -1) {
                    if (cur.get(split[i]) == null)
                        cur.put(split[i],type);
                } else {
                    Map map = (Map)cur.get(split[i]);
                    if (map == null) {
                        map = new HashMap<>();
                        if (cur.get(split[i]) == null)
                            cur.put(split[i],map);
                    }
                    cur = map;
                }
            }
        }
        return jsonDataTpl;
    }

    /**
     * 把filter的字段属性也转换成jsonDataTpl数据模板
     * @param jsonDataTpl
     * @param filterInfo
     * @return
     */
    private Map<String,Object> filter2JsonDataTpl(Map<String,Object> jsonDataTpl,FilterInfo filterInfo) {
        if (filterInfo == null || filterInfo.isEmpty())  return jsonDataTpl;
        FilterItemCollection filterItemCol = filterInfo.getFilterItemCollection();
        for (int i = 0, len = filterItemCol.size(); i < len; i++) {
            FilterItemInfo filterItemInfo = filterItemCol.get(i);
            if (PKPublicUtils.equals(ValueTypeEnum.SQL,filterItemInfo.getValueType())) continue;
            String compareExpr = filterItemInfo.getCompareExpr();
            jsonDataTpl = property2JsonDataTpl(jsonDataTpl,compareExpr, JsonTplDataType.Filter);

            //扩展的属性映射
            ListMap<String> propertyMapping = filterItemInfo.getPropertyMappingEx();
            for (int j = 0, jLen = propertyMapping.size(); j < jLen; j++) {
                String property = propertyMapping.get(j);
                jsonDataTpl = property2JsonDataTpl(jsonDataTpl,property,JsonTplDataType.Filter);
            }
        }
        FilterInfo mergeFilterInfo = filterInfo.getMergeFilterInfo();
        if (mergeFilterInfo != null) return filter2JsonDataTpl(jsonDataTpl,mergeFilterInfo);
        return jsonDataTpl;
    }

    /**
     * 把sorter的字段属性也转换成jsonDataTpl数据模板
     * @param jsonDataTpl
     * @param sorterItemCol
     * @return
     */
    private Map<String,Object> sorter2JsonDataTpl(Map<String,Object> jsonDataTpl, SorterItemCollection sorterItemCol) {
        if (sorterItemCol == null || sorterItemCol.isEmpty()) return jsonDataTpl;
        for (int i = 0, len = sorterItemCol.size(); i < len; i++) {
            SorterItemInfo sorterItemInfo = sorterItemCol.get(i);
            String sorterField = sorterItemInfo.getProperyName();
           jsonDataTpl = property2JsonDataTpl(jsonDataTpl,sorterField,JsonTplDataType.Sorter);
        }
        return jsonDataTpl;
    }

    /**
     *  将jsonDataTpl解析成SelectorMap;
     * @param jsonDataTpl
     * @param entityClass
     * @param lTblSelectorMap  左表的selector
     * @param longFieldAliasPrefix 字段别名前缀,join情况下需要把joinTable的字段作为长前缀 
     * @return
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
	private SelectorMap parseJsonDataTpl2SelectorMap(Map<String,Object> jsonDataTpl, Class<?> entityClass, SelectorMap lTblSelectorMap,String longFieldAliasPrefix) {
        SelectorMap selectorMap = new SelectorMap();
        selectorMap.setTableAlias("T" + tableAliasIdx);
        tableAliasIdx++;
        selectorMap.setLTblSelectorMap(lTblSelectorMap);
        selectorMap.setEntityClass(entityClass);
        longFieldAliasPrefix = longFieldAliasPrefix == null ? "" : longFieldAliasPrefix;;
        selectorMap.setLongFieldAliasPrefix(longFieldAliasPrefix);

        Iterator<String> itKey = jsonDataTpl.keySet().iterator();
        NoCaseMap<Field> mapFieldMapping = PKClassUtils.getAllField(entityClass);
        selectorMap.setFieldMapping(mapFieldMapping);
        while(itKey.hasNext()) {
            String key = itKey.next();
            Object dataTplType = jsonDataTpl.get(key);
            Field field = mapFieldMapping.get(key);
            if (field == null) throw PKDevException.throwException("Entity实体类[%s]不存在映射字段[%s]",entityClass.getName(),key);
            Annotation[] anns = field.getAnnotations();
            if (anns != null && anns.length == 1 && anns[0] instanceof Transient) continue;
            
            if (dataTplType instanceof JsonTplDataType) {
                Annotation ann = field.getAnnotation(Column.class);
                if (ann == null) throw PKDevException.throwException("Entity实体类[%s]映射字段[%s]缺少Column注解",entityClass.getName(),key);
                String fieldName = ((Column)ann).name();
                if (PKPublicUtils.equals(JsonTplDataType.Selector,dataTplType)) {
                    SelectorField selectorField = new SelectorField();
                    selectorField.setFieldName(fieldName);
                    selectorField.setShortFieldAlias(key);
                    selectorMap.addField(selectorField);
                }
                String key1  = (PKPublicUtils.isEmpty(selectorMap.getLongFieldAliasPrefix()) ? ""  : (selectorMap.getLongFieldAliasPrefix() + longFieldAliasSplit ))+ key;
                String value1 = selectorMap.getTableAlias() + "." + fieldName;
                propertyFieldMapping.put(key1,value1);
            }  else if (dataTplType instanceof Map) {
                if (((Map) dataTplType).size() == 1 && ((Map) dataTplType).get("id") != null)  {
                    Annotation ann = field.getAnnotation(JoinColumn.class);
                    if (ann == null) throw PKDevException.throwException("Entitys实体类型[%s]映射字段[%s]缺少JoinColumn注解",entityClass.getName(),key);
                    String fieldName = ((JoinColumn)ann).name();
                    if (PKPublicUtils.equals(JsonTplDataType.Selector,((Map) dataTplType).get("id"))) {
                        SelectorField selectorField = new SelectorField();
                        selectorField.setFieldName(fieldName);
                        selectorField.setShortFieldAlias(key + ".id");
                        selectorMap.addField(selectorField);
                        
                        String key1  =  (PKPublicUtils.isEmpty(selectorMap.getLongFieldAliasPrefix()) ? "" : (selectorMap.getLongFieldAliasPrefix() + longFieldAliasSplit)) + key + longFieldAliasSplit + "id";
                        String value1 = selectorMap.getTableAlias() + "." + fieldName;
                        propertyFieldMapping.put(key1,value1);
                    } else if (PKPublicUtils.equals(JsonTplDataType.Filter,((Map)dataTplType).get("id"))) {
                        String key1  =  (PKPublicUtils.isEmpty(selectorMap.getLongFieldAliasPrefix()) ? "" : (selectorMap.getLongFieldAliasPrefix() + longFieldAliasSplit)) + key + longFieldAliasSplit + "id";
                        String value1 = selectorMap.getTableAlias() + "." + fieldName;
                        propertyFieldMapping.put(key1,value1);
                    }

                } else {
                    Class clazz = field.getType();
                    boolean isListField = List.class.isAssignableFrom(clazz);
                    if (isListField) {
                        clazz = PKClassUtils.getGenericClass(field);
                    }
                    longFieldAliasPrefix = PKPublicUtils.isEmpty(selectorMap.getLongFieldAliasPrefix()) ? key : (selectorMap.getLongFieldAliasPrefix() + longFieldAliasSplit + key);
                    SelectorMap rTblSelectorMap = parseJsonDataTpl2SelectorMap((Map)dataTplType, clazz, selectorMap,longFieldAliasPrefix);
                    rTblSelectorMap.setLTblField(field);
                    String fieldAliasPrefix = field.getName();
                    rTblSelectorMap.setShortFieldAliasPrefix(fieldAliasPrefix);
                    selectorMap.addRTblSelectorMap(rTblSelectorMap.getShortFieldAliasPrefix(),rTblSelectorMap);
                    //如果是select包含分录集合时，需将表头的FID以及分录的FParentID自动添加到select中，在转换成对象时需要用到
                    if (isListField)  {
                        SelectorField idSelectorField = new SelectorField();
                        idSelectorField.setFieldName("FID");
                        idSelectorField.setShortFieldAlias("id");
                        selectorMap.addField(idSelectorField);
                        SelectorField parentIdSelectorField = new SelectorField();

                        Annotation ann = field.getAnnotation(JoinColumn.class);
                        if (ann == null) throw PKDevException.throwException("Entity实体类[%s]映射字段[%s]缺少JoinColumn注解",entityClass.getName(),key);
                        String dbField = ((JoinColumn)ann).name();
                        NoCaseMap<Field> rTblFieldMapping = PKClassUtils.getAllField(rTblSelectorMap.getEntityClass());
                        Iterator<String> rTblIT=  rTblFieldMapping.keySet().iterator();
                        while (rTblIT.hasNext()) {
                            String rTblFieldName = rTblIT.next();
                            Field rTblField = rTblFieldMapping.get(rTblFieldName);
                            Annotation rTblAnn = rTblField.getAnnotation(JoinColumn.class);
                            if (rTblAnn == null) continue;
                            String rTblDBField = ((JoinColumn) rTblAnn).name();
                            if (PKPublicUtils.equalsIgnoreCase(dbField, rTblDBField)) {
                                parentIdSelectorField.setShortFieldAlias(rTblFieldName + ".id");
                                break;
                            }
                        }
                        if (PKPublicUtils.isEmpty(parentIdSelectorField.getShortFieldAlias()))
                            throw PKDevException.throwException("分录Entity实体类[%s]缺少与主Entity实体类[%s]相呼应的属性字段[%s]关系",rTblSelectorMap.getEntityClass().getName(),selectorMap.getEntityClass().getName(),dbField);
                        parentIdSelectorField.setFieldName(dbField);

                        rTblSelectorMap.addField(parentIdSelectorField);
                    }

                }

            } else {
                throw PKDevException.throwException("暂不支持格式类型[%s]",dataTplType.getClass().getName());
            }

        }
        return selectorMap;
    }

    private void builderSQL(SelectorMap selectorMap) {
        if (selectorMap == null) return;
        String tableAlias = selectorMap.getTableAlias();
        //select 字段
        ListMap<SelectorField> lstRSelectorField = selectorMap.getSelectorFields();
        for (int i = 0, len = lstRSelectorField.size(); i < len; i++) {
            SelectorField rSelectorField = lstRSelectorField.get(i);
            String fieldName = rSelectorField.getFieldName();
            String fieldAlias = rSelectorField.getShortFieldAlias();
            String allFieldAliasPrefix = selectorMap.getShortFieldAliasPrefix();
            SelectorMap lSelectorMap = selectorMap.getLTblSelectorMap();
            while (lSelectorMap!= null) {
                allFieldAliasPrefix =  lSelectorMap.getShortFieldAliasPrefix() == null ? allFieldAliasPrefix : (lSelectorMap.getShortFieldAliasPrefix() + "." + allFieldAliasPrefix);
                lSelectorMap = lSelectorMap.getLTblSelectorMap();
            }
            sqlSelectField.append(tableAlias).append(".").append(fieldName).append(" \"").append(allFieldAliasPrefix).append(".").append(fieldAlias).append("\",");
            selectFieldCount++;
            if (selectFieldCount % 5 == 0)  sqlSelectField.append(CR);
        }

        //join table 关联table
        //左表
        SelectorMap lTblSelectorMap = selectorMap.getLTblSelectorMap();
        Class<?> lEntityClass = lTblSelectorMap.getEntityClass();
        String lTableAlias = lTblSelectorMap.getTableAlias();
        Field lField = selectorMap.getLTblField();
        Annotation lAnn = lField.getAnnotation(JoinColumn.class);
        if (lAnn == null) throw PKDevException.throwException("Entity实体类[%s]映射字段[%s]缺少JoinColumn注解",lEntityClass.getName(),lField.getName());
        String lFieldName = ((JoinColumn)lAnn).name();

        //右表
        String rTableName = PKClassUtils.getTableName(selectorMap.getEntityClass());
        String rTableAlias = selectorMap.getTableAlias();
        if (List.class.isAssignableFrom(lField.getType())) {
            sqlInnerTable.append("left join ").append(rTableName).append(" ").append(rTableAlias)
                    .append(" on ").append(rTableAlias).append(".").append(lFieldName).append("=").append(lTableAlias).append(".FID").append(CR);
        } else {
            sqlInnerTable.append("left join ").append(rTableName).append(" ").append(rTableAlias)
                    .append(" on ").append(rTableAlias).append(".FID=").append(lTableAlias).append(".").append(lFieldName).append(CR);
        }
        
        ListMap<SelectorMap> lstRTblSelectorMap = selectorMap.getRTblSelectorMap();
        for (int i = 0, len = lstRTblSelectorMap.size(); i < len; i++) {
            SelectorMap rTblSelectorMap = lstRTblSelectorMap.get(i);
            builderSQL(rTblSelectorMap);
        }
    }

    /**
     * 解析完善FitlerInfo
 	 * 增补实际dbField
     * @param filterInfo
     */
    private void reParseFilterInfo(FilterInfo filterInfo) {
        FilterItemCollection filterItemCol = filterInfo.getFilterItemCollection();
        for (int i = 0, len = filterItemCol.size(); i < len; i++) {
            FilterItemInfo filterItemInfo = filterItemCol.get(i);
            if (PKPublicUtils.equals(ValueTypeEnum.SQL,filterItemInfo.getValueType())) continue;
            String compareExpr = filterItemInfo.getCompareExpr();
            String dbField = propertyFieldMapping.get(compareExpr);
            filterItemInfo.setDbField(dbField);
            ListMap<String> propertyMappingEx = filterItemInfo.getPropertyMappingEx();
            for (int j = 0, jLen = propertyMappingEx.size(); j < jLen; j++) {
                String propertyEx = propertyMappingEx.get(j);
                String dbFieldEx = propertyFieldMapping.get(propertyEx);
                propertyMappingEx.add(propertyEx,dbFieldEx);
            }
        }
        if (filterInfo.getMergeFilterInfo() != null) reParseFilterInfo(filterInfo.getMergeFilterInfo());
    }

    /**
     * 解析完善SortItemCollection
 	 * 增补实际dbField
     * @param sorterItemCol
     */
    private void reParseSorter(SorterItemCollection sorterItemCol) {
        for (int i = 0, len = sorterItemCol.size(); i < len; i++) {
            SorterItemInfo sorterItemInfo = sorterItemCol.get(i);
            String field = sorterItemInfo.getProperyName();
            String dbField = propertyFieldMapping.get(field);
            sorterItemInfo.setDbField(dbField);
        }
    }

    /**
     * TODO 后续考虑增加支持格式"id,number,permitemPO.id,permitemPO.name"
     * selector字串的格式
     * "{id,number,name,permitemPO:{id,name},seqNo,parent:{id,name,number,creator:{id,password}},remark,creator:{name,number}}";
     * 
     * 将selector字串转换成SelectorItemCollection对象
     * @param selector
     * @return
     */
    public SelectorItemCollection toSelectorItemCol(String selector) {
        SelectorItemCollection sic = new SelectorItemCollection();
        char[] c = selector.toCharArray();
        StringBuilder parent = new StringBuilder();
        StringBuilder item = new StringBuilder();
        for (int i = 0,len = c.length; i < len; i++) {
            if (c[i] == 123) continue;  // '{' --> 123
            else if (c[i] == 44) {  // ',' --> 44
                String s = parent.toString().replace("#","") + item.toString();
                if (s.length() == 0) continue;
                SelectorItemInfo sii = new SelectorItemInfo(s);
                sic.addSelectorItemInfo(sii);
                item.delete(0,item.length());
            } else if (c[i] == 58) { // ':' --> 58
                parent.append("#").append(item.toString()).append(".");
                item.delete(0,item.length());
            } else if (c[i] ==125) {   // '}' --> 125
                if (item.length() > 0) {
                    String s = parent.toString().replace("#","") + item.toString();
                    SelectorItemInfo sii = new SelectorItemInfo(s);
                    sic.addSelectorItemInfo(sii);
                }
                item.delete(0,item.length());
                parent.delete(parent.lastIndexOf("#") < 0 ? 0 : parent.lastIndexOf("#"),parent.length());
                String[] p = parent.toString().split("\\.");
                for (int j = 0; j < p.length -1; j++) {
                    parent.append(p[j]);
                }
            } else item.append(c[i]);
        }

        return sic;
    }

    /**
     * 完整的select查询对象,selectorMap包含select语句完整信息
     * 最终解析成SQL的依据
     * 
     * @author jinbin_guo  2019年4月17日 下午2:24:17
     *
     */
    @SuppressWarnings("serial")
    @Getter
    @Setter
    private class SelectorMap implements Serializable {

        /** entity class */
        private Class<?> entityClass;
        /** table别名*/
        private String tableAlias;
        /** selector 字段明细 */
        private ListMap<SelectorField> lstSelectorField = new ListMap<>();

        /** 关联中左边Table对应的SelectorMap */
        private SelectorMap lTblSelectorMap;
        /** 关联中左边Table对应的字段 */
        private Field lTblField;

        /** 关联中右边Table对应的SelectorMap */
        private ListMap<SelectorMap> rTblSelectorMap = new ListMap<>();

        /** 字段别名前缀,join情况下需要把joinTable的字段作为短前缀 */
        private String shortFieldAliasPrefix;

        /** 字段别名前缀,join情况下需要把joinTable的字段作为长前缀 */
        private String longFieldAliasPrefix;

        /** poClass 字段映射 key=字段名*/
        private Map<String,Field> fieldMapping;
        
        
        public ListMap<SelectorField> getSelectorFields() {
            return lstSelectorField;
        }
        public void addField(SelectorField selectorField) {
            lstSelectorField.add(selectorField.getShortFieldAlias(),selectorField);
        }
        public void addRTblSelectorMap(String key,SelectorMap selectorMap) {
            rTblSelectorMap.add(key,selectorMap);
        }
    }

    @SuppressWarnings("serial")
	@Getter
    @Setter
    private class SelectorField implements Serializable {

        /**原始实体属性值 */
        private String orginalProperty;
        /** 字段 */
        private String fieldName;
        /** 字段短别名 对于关联table时,系统将左表关联的字段名加进来,如parent_id,parent_creator_name*/
        private String shortFieldAlias;
    }

    /**
     * 
     * JsonTpl模板数据类型
     * @author jinbin_guo  2019年4月17日 下午1:46:50
     *
     */
    private enum JsonTplDataType {
    	Selector,Filter,Sorter
    } 
}
